package main

import (
	"fmt"
	"math/rand"
	"sync"
	"time"
)

func main() {
	fmt.Println("15. 协程 (Goroutines)")

	// 什么是协程
	fmt.Println("\n--- 什么是协程 ---")

	// 普通函数调用
	fmt.Println("开始执行普通函数:")
	sayHelloSync()
	sayHelloSync()
	sayHelloSync()
	fmt.Println("普通函数执行完毕\n")

	// 协程调用
	fmt.Println("开始执行协程:")
	go sayHelloAsync() // 启动一个协程
	go sayHelloAsync() // 启动另一个协程
	go sayHelloAsync() // 启动第三个协程

	// 给协程一些时间执行完毕
	time.Sleep(100 * time.Millisecond)
	fmt.Println("主协程继续执行")

	// 协程与主协程的执行顺序
	fmt.Println("\n--- 协程与主协程的执行顺序 ---")
	fmt.Println("主协程开始")

	// 启动一个协程
	go func() {
		fmt.Println("协程执行")
	}()

	fmt.Println("主协程结束")
	// 注意：上面的协程可能没有执行，因为主协程执行完就退出了

	// 修复上面的问题
	fmt.Println("\n--- 确保协程执行完毕 ---")
	fmt.Println("主协程开始")

	// 使用 WaitGroup 等待协程执行完毕
	var wg sync.WaitGroup
	wg.Add(1)

	go func() {
		defer wg.Done()
		fmt.Println("协程执行完毕")
	}()

	wg.Wait()
	fmt.Println("主协程结束")

	// 协程的实际应用示例
	fmt.Println("\n--- 协程的实际应用示例 ---")

	// 并发执行多个任务
	var wg2 sync.WaitGroup
	tasks := []string{"任务1", "任务2", "任务3", "任务4", "任务5"}

	for _, task := range tasks {
		wg2.Add(1)
		go func(t string) {
			defer wg2.Done()
			processTask(t)
		}(task)
	}

	wg2.Wait()
	fmt.Println("所有任务执行完毕")

	// 协程与循环变量
	fmt.Println("\n--- 协程与循环变量 ---")

	// 错误示例：直接使用循环变量
	fmt.Println("错误示例:")
	for i := 1; i <= 3; i++ {
		go func() {
			fmt.Printf("协程 %d\n", i) // 这里的 i 可能不是期望的值
		}()
	}
	time.Sleep(10 * time.Millisecond)

	// 正确示例1：将循环变量作为参数传递
	fmt.Println("正确示例1:")
	for i := 1; i <= 3; i++ {
		go func(n int) {
			fmt.Printf("协程 %d\n", n)
		}(i)
	}
	time.Sleep(10 * time.Millisecond)

	// 正确示例2：在循环内部创建变量
	fmt.Println("正确示例2:")
	for i := 1; i <= 3; i++ {
		i := i // 在循环内部创建新变量
		go func() {
			fmt.Printf("协程 %d\n", i)
		}()
	}
	time.Sleep(10 * time.Millisecond)

	// 协程的数量和性能
	fmt.Println("\n--- 协程的数量和性能 ---")

	// 创建大量协程
	var wg3 sync.WaitGroup
	numGoroutines := 1000

	fmt.Printf("创建 %d 个协程...\n", numGoroutines)
	start := time.Now()

	for i := 0; i < numGoroutines; i++ {
		wg3.Add(1)
		go func(id int) {
			defer wg3.Done()
			// 模拟一些工作
			time.Sleep(time.Millisecond)
		}(i)
	}

	wg3.Wait()
	elapsed := time.Since(start)
	fmt.Printf("所有 %d 个协程执行完毕，耗时: %v\n", numGoroutines, elapsed)

	// 协程与资源竞争
	fmt.Println("\n--- 协程与资源竞争 ---")

	// 不安全的并发访问
	counter := 0
	var wg4 sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg4.Add(1)
		go func() {
			defer wg4.Done()
			counter++ // 这里存在资源竞争
		}()
	}

	wg4.Wait()
	fmt.Printf("不安全的计数器结果: %d (期望: 1000)\n", counter)

	// 安全的并发访问（使用互斥锁）
	var mutex sync.Mutex
	safeCounter := 0
	var wg5 sync.WaitGroup

	for i := 0; i < 1000; i++ {
		wg5.Add(1)
		go func() {
			defer wg5.Done()
			mutex.Lock()
			safeCounter++
			mutex.Unlock()
		}()
	}

	wg5.Wait()
	fmt.Printf("安全的计数器结果: %d (期望: 1000)\n", safeCounter)

	// 协程的生命周期管理
	fmt.Println("\n--- 协程的生命周期管理 ---")

	// 使用通道控制协程生命周期
	stop := make(chan bool)

	go func() {
		for {
			select {
			case <-stop:
				fmt.Println("协程收到停止信号，退出")
				return
			default:
				fmt.Print(".")
				time.Sleep(500 * time.Millisecond)
			}
		}
	}()

	time.Sleep(3 * time.Second)
	stop <- true
	fmt.Println("\n已发送停止信号")

	// 协程池示例
	fmt.Println("\n--- 协程池示例 ---")
	jobQueue := make(chan int, 10)
	workerCount := 3

	// 启动工作协程
	for i := 0; i < workerCount; i++ {
		go worker(i, jobQueue)
	}

	// 发送任务
	for i := 1; i <= 5; i++ {
		jobQueue <- i
	}
	close(jobQueue) // 关闭任务队列

	// 等待一段时间让工作协程处理完任务
	time.Sleep(2 * time.Second)
	fmt.Println("协程池示例结束")
}

// 同步函数
func sayHelloSync() {
	fmt.Println("Hello, Sync!")
}

// 异步函数（用于协程）
func sayHelloAsync() {
	fmt.Println("Hello, Async!")
}

// 模拟任务处理
func processTask(taskName string) {
	// 模拟随机处理时间
	delay := time.Duration(rand.Intn(500)) * time.Millisecond
	time.Sleep(delay)
	fmt.Printf("完成 %s，耗时 %v\n", taskName, delay)
}

// 工作协程
func worker(id int, jobs <-chan int) {
	for job := range jobs {
		fmt.Printf("工作协程 %d 正在处理任务 %d\n", id, job)
		time.Sleep(time.Second) // 模拟工作
		fmt.Printf("工作协程 %d 完成任务 %d\n", id, job)
	}
}
